#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEAdvertisedDevice.h>

// 服务和特征UUID
constexpr auto SERVICE_UUID_STR = "0000ffe0-0000-1000-8000-00805f9b34fb";
constexpr auto CHARACTERISTIC_UUID_STR = "0000ffe1-0000-1000-8000-00805f9b34fb";
// 指定的蓝牙设备地址和名称
// const char *const TARGET_ADDRESS = "78:77:87:01:ec:d2";
const char *const TARGET_ADDRESS = "c8:47:80:5B:c5:d3";
const char *const TARGET_DEVICE_NAME = "<XDBMS-25052566>";

// 数据完整性状态标志
bool full = false;
// 连接状态标志
bool isConnected = false;
// 数据完整性状态标志
bool fullConnected = false;
// 客户端、设备及特征指针
BLEClient *pClient = nullptr;
BLEAdvertisedDevice *pServer = nullptr;
BLERemoteCharacteristic *pRemoteCharacteristic = nullptr;

// 存储累积的数据
std::vector<uint8_t> accumulatedData;
// 预期的头字节序列（两个字节）
const uint8_t HEADER_BYTES[2] = {0x01, 0x03};
// 完整数据的长度
size_t FULL_DATA_LENGTH = 128;
// 超时时间（单位：毫秒）
const unsigned long TIMEOUT_VALUE = 1000;
// 记录开始接收数据的时间
unsigned long receiveStartTime = 0;

// 搜索到设备时的回调类
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
  void onResult(BLEAdvertisedDevice advertisedDevice) override
  {
    if (advertisedDevice.getName() == TARGET_DEVICE_NAME || advertisedDevice.getAddress().toString() == TARGET_ADDRESS)
    {
      // 停止扫描
      advertisedDevice.getScan()->stop();
      // 暂存设备
      pServer = new BLEAdvertisedDevice(advertisedDevice);
      // 设置连接标志
      isConnected = false;
    }
    Serial.print("getName: ");
    Serial.println(advertisedDevice.getName().c_str());
    Serial.print("getAddress: ");
    Serial.println(advertisedDevice.getAddress().toString().c_str());
    displayer7.display(85, 302, String(advertisedDevice.getAddress().toString().c_str()), 1, 2, TFT_WHITE);
  }
};

// 客户端连接与断开的回调类
class MyClientCallback : public BLEClientCallbacks
{
  void onConnect(BLEClient *pclient) override {}
  void onDisconnect(BLEClient *pclient) override
  {
    isConnected = false;
    fullConnected = false;
    Serial.println("蓝牙已断开");
  }
};

// 将uint8数组转换为十六进制字符串
bool uint8_array_to_hex_string(const uint8_t *array, int length, char *output)
{
  if (output == nullptr)
  {
    Serial.println("输出缓冲区指针为空");
    return false;
  }
  for (int i = 0; i < length; i++)
  {
    if (sprintf(output + (i * 2), "%02X", array[i]) < 0)
    {
      Serial.println("转换十六进制字符串时出错");
      return false;
    }
  }
  return true;
}
// CRC16计算函数
uint16_t crc16(const std::vector<uint8_t> &data)
{
  uint16_t crc = 0xFFFF;
  const uint16_t polynomial = 0xA001;
  for (size_t i = 0; i < data.size(); i++)
  {
    crc ^= data[i];
    for (int j = 0; j < 8; j++)
    {
      if (crc & 0x0001)
      {
        crc = (crc >> 1) ^ polynomial;
      }
      else
      {
        crc >>= 1;
      }
    }
  }
  // 结果反转
  crc = (crc << 8) | (crc >> 8);
  return crc;
}

// 向BLE服务器发送数据
void sendtoBLEServer()
{
  static int a = 0;
  std::string hexData = "";
  if (pRemoteCharacteristic != nullptr && pRemoteCharacteristic->canWrite())
  {
    hexData = "01030000001D85C3"; //  第一页读取代码
    // 将十六进制字符串转换为字节数组
    std::vector<uint8_t> bytes;
    for (size_t i = 0; i < hexData.length(); i += 2)
    {
      std::string byteString = hexData.substr(i, 2);
      char *endPtr;
      uint8_t byte = static_cast<uint8_t>(strtoul(byteString.c_str(), &endPtr, 16));
      if (*endPtr != '\0')
      {
        Serial.println("十六进制字符串转换为字节时出错");
        return;
      }
      bytes.push_back(byte);
    }
    // 发送数据
    pRemoteCharacteristic->writeValue(bytes.data(), bytes.size());
  }
}

// 收到服务推送数据时的回调函数
void NotifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify)
{
  if (accumulatedData.empty())
  {
    receiveStartTime = millis();
  }
  // Serial.println("pData:");
  for (size_t i = 0; i < length; i++)
  {
    // Serial.print(pData[i], HEX);
    accumulatedData.push_back(pData[i]);
  }
  // Serial.println("");

  // 这里简单判断数据长度是否至少包含头字节和校验码

  if (accumulatedData.size() == 63)
  {
    fullConnected = false;
    // 获取接收到的校验码（最后两个字节）
    uint16_t receivedChecksum = (accumulatedData[accumulatedData.size() - 2] << 8) + accumulatedData[accumulatedData.size() - 1];
    std::vector<uint8_t> dataForChecksum(accumulatedData.begin(), accumulatedData.end() - 2);
    uint16_t calculatedChecksum = crc16(dataForChecksum);
    char hex_string[dataForChecksum.size() * 2 + 1];
    if (uint8_array_to_hex_string(dataForChecksum.data(), dataForChecksum.size(), hex_string))
    {
      if (receivedChecksum == calculatedChecksum)
      {
        // Serial.println("完整且校验通过的数据: ");
        // Serial.println(hex_string);
        // 用于存储不同标志数据的数组
        std::vector<int> array1;
        std::vector<int> array2;
        std::vector<int> array3;

        // 进行数据拆分处理，每两个字节一组转化为十进制
        for (size_t j = 3; j < accumulatedData.size() - 2; j += 2)
        {

          int value = (accumulatedData[j] << 8) + accumulatedData[j + 1];
          // Serial.print(j);
          // Serial.print("-");
          // Serial.print(value);
          // Serial.print("# ");
          if (j <= 13)
          {
            array1.push_back(value);
          }
          else if (j >= 15 && j <= 19)
          {
            array2.push_back(value);
          }
          else if (j >= 21 && j <= 59)
          {
            array3.push_back(value);
          }
        }
        voltage = array1[0];
        batteryLevel = array1[2];
        if (array1[5] & 0x8000)
        {
          current = -((~array1[5]) & 0xFFFF) + 1;
        }
        else
        {
          current = array1[5];
        }
        temperature = *std::max_element(array2.begin(), array2.end());
        minVoltage = *std::min_element(array3.begin(), array3.end());
        maxVoltage = *std::max_element(array3.begin(), array3.end());
        voltageDiff = maxVoltage - minVoltage;
        accumulatedData.clear(); // 清空，准备接收下一组数据
        full = true;
        f5++;
      }
    }
    else
    {
      Serial.println("数据校验失败: ");
      Serial.println("原校验码：" + String(receivedChecksum));
      Serial.println("计算校验码：" + String(calculatedChecksum));
      sendtoTCPServer("cmd=2&uid=" + UID + "&topic=" + TOPIC + "&msg=数据校验失败\r\n"); // 推送消息
    }
  }
  // Serial.println("");
  // Serial.println("电量: " + String(batteryLevel));
  // Serial.println("电压: " + String(voltage));
  // Serial.println("电流: " + String(current));
  // Serial.println("温度: " + String(temperature));
  // Serial.println("最高单体电压: " + String(maxVoltage));
  // Serial.println("最低单体电压: " + String(minVoltage));
}

// 连接设备并获取服务与特征
bool ConnectToServer()
{
  pClient = BLEDevice::createClient();
  if (pClient == nullptr)
  {
    Serial.println("创建客户端失败");
    return false;
  }
  pClient->setClientCallbacks(new MyClientCallback());

  if (pServer == nullptr)
  {
    Serial.println("未找到目标设备");
    return false;
  }

  if (!pClient->connect(pServer))
  {
    Serial.println("连接设备失败");
    return false;
  }
  Serial.println("连接设备成功");

  BLERemoteService *pRemoteService = pClient->getService(SERVICE_UUID_STR);
  if (pRemoteService == nullptr)
  {
    Serial.println("获取服务失败");
    pClient->disconnect();
    return false;
  }
  Serial.println("获取服务成功");

  pRemoteCharacteristic = pRemoteService->getCharacteristic(CHARACTERISTIC_UUID_STR);
  if (pRemoteCharacteristic == nullptr)
  {
    Serial.println("获取特性失败");
    pClient->disconnect();
    return false;
  }
  Serial.println("获取特征成功");

  // if (pRemoteCharacteristic->canRead())
  // {
  //   Serial.printf("该特征值可以读取并且当前值为: ");
  //   std::string value = pRemoteCharacteristic->readValue();
  //   for (char c : value)
  //   {
  //     Serial.printf("%02X ", (unsigned char)c);
  //   }
  //   Serial.println();
  // }
  if (pRemoteCharacteristic->canNotify())
  {
    pRemoteCharacteristic->registerForNotify(NotifyCallback);
  }
  return true;
}

// 初始化蓝牙扫描
void initble()
{
  BLEDevice::init("");
  BLEScan *pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(80);
}
// 启动蓝牙相关操作
void qidongble()
{
  if (!isConnected)
  {
    BLEDevice::getScan()->clearResults();
    BLEDevice::getScan()->start(1, false); // 扫描5秒
    if (pServer != nullptr)
    {
      if (ConnectToServer())
      {
        isConnected = true;
        setuptft();
      }
    }
  }
  else
  {

    if (!fullConnected)
    {
      sendtoBLEServer();
      fullConnected = true;
    }
    else
    {
      if (!accumulatedData.empty() && millis() - receiveStartTime > TIMEOUT_VALUE)
      {
        sendtoBLEServer();
        receiveStartTime = millis();
      }
    }
    if (full)
    {
      qidongtft();
      print_current_time();
    }
  }
}